【小ネタ】CircleCIのManual Approvalを利用したシンプルなブランチ/タグ運用
はじめに
こんにちは、中山です。
私が現在関わっている案件ではCircleCIを利用してAWS SAMで管理されたサーバーレスアプリケーションのCI/CDを整えています。ご存じの方も多いかと思いますが、CircleCIは去年2.0を発表しその機能を大きくアップデートしてくれました。Dockerを全面的に取り入れたアーキテクチャに変わっていたり、ローカルでの実行などもサポートされ日々便利に使っています。
今回は、そんなアップデートの内Manual Approvalについてご紹介したいと思います。この機能はワークフローに静止点を作ってくれるものなのですが、これを応用して複雑になっていたブランチ/タグ運用をシンプルにできた事例についてご紹介します。
今までの課題
私が関わっている案件ではGitのブランチ運用をGitHubフローにしています。つまり、フィーチャーブランチを master
ブランチからチェックアウト → PR → レビュー → マージというおなじみのフローです。GitHubフローはGitフローに比べてブランチ運用がシンプルになるので好きなのですが、リリースする際どうするかが課題でした。
今の案件では4環境(開発/結合/ステージング/本番)存在するため、 master
ブランチだけでは上手くリリースができません。例えば、 master
ブランチにマージされると全環境へデプロイが走ってもらっては困ります。本番環境へ適用する前に他の環境でしっかりとテストするという流れにしないと思わぬバグを検知できません。もちろん、あるべき論で言えばフィーチャーフラグなどを利用して同じコードでも異なる振る舞いにすべきなのかもしれませんが、まだそこまで作り込めてないのです。
そこで以前までは以下のような方式を検討/実施していました。
1. GitHubフロー + タグリリース
デプロイは以下のフローで実施します。
master
ブランチにマージされると開発環境にデプロイされるv1.0.0-itg
などのタグをPushすると結合環境にデプロイされるv1.0.0-stg
などのタグをPushするとステージング環境にデプロイされるv1.0.0
などのタグをPushすると本番環境にデプロイされる
master
は頻繁に更新されるので開発環境と結びつけ、簡単にリリースできるようにしています。結合/ステージング/本番にはそれぞれ専用のタグをひも付けし、それらをPushした場合にデプロイされるようにしています。考えた当初は上手く設計できたかなと無邪気に思っていたのですが、何度かリリースしていくうちに以下のような課題が発生していました。
- タグ打つのがシンドい
- タグに環境名がついているのって何か使い方間違ってないか
- タグを打つにはローカルPCにコードをPullしてくる必要があるが、たまに忘れて古いコミットにタグ打つ場合がある
特に3つ目が微妙でリリース時にオペミスを誘発する原因となっていました。計3回もタグ打っていればさすがにミスも起きますよね…
2. GitHubフロー + タグリリース + リリースブランチ
先程の反省を元に以下のような構成も考えてみました。
デプロイは以下のフローで実施します。
master
ブランチにマージされると開発環境にデプロイされるintegration
ブランチにマージすると結合環境にデプロイされるstaging
ブランチにマージするとステージング環境にデプロイされるv1.0.0
などのタグをPushすると本番環境にデプロイされる
こちらも同様 master
ブランチは開発環境とひも付けます。そして、結合/ステージングにそれぞれ integration
/ staging
というリリース用ブランチを、本番用にリリース用のタグをひも付けるという構成です。タグを打つ機会が1度に減ったため、オペミスが発生する可能性を低減できているかなぁと思って設計してみたのですが、リリースの度にいちいちPR出すのシンドいという問題が発生…こっちはそもそも試してもないです。見るからにダメそうなので。
Manual Approvalを利用したブランチ/タグ運用
どうしたものかなと思っていたのですが、CircleCI2.0からManual Approvalなる機能があることを聞きつけ調べてみると結構使えそうだと判明。この機能を使って最終的に以下のような構成に行き着きました。
デプロイは以下のフローで実施します。つまり、 余計なブランチ/タグが増えない形で重要な環境へデプロイする前にテストする時間を設けること が実現できました。
- フィーチャーブランチはユニットテストまで実行
master
ブランチにマージされると開発環境にデプロイされるmaster
ブランチのManual Approvalを承認すると結合環境にデプロイされるv1.0.0
などのタグをPushするとステージング環境にデプロイされる- タグのManual Approvalを承認すると本番環境にデプロイされる
CircleCIの設定ファイル( .circleci/config.yml
)は以下のようになります。
workflows: version: 2 my_workflow: jobs: - guess_and_save_aws_envs: filters: tags: only: /.*/ - build_and_test_unit: requires: - guess_and_save_aws_envs filters: tags: only: /.*/ - deploy_and_test_e2e: requires: - build_and_test_unit filters: branches: only: - master tags: only: /v([0-9]+\.){2}[0-9]+/ - approve_deploy: type: approval requires: - deploy_and_test_e2e filters: branches: only: - master tags: only: /v([0-9]+\.){2}[0-9]+/ - approved_deploy_and_test_e2e: requires: - approve_deploy filters: branches: only: - master tags: only: /v([0-9]+\.){2}[0-9]+/
Approval待ちの状態は以下のように「ON HOLD」という状態になり、デプロイを停止してくれます。しっかりテストを実施した後に紫色の画面を押してデプロイすることによって安全に別の環境にデプロイすることができます。最高。
ロールバックしにくくなるのでは?
本エントリを読んでいただいた方の中には「この構成だとロールバックしにくくならない?」と思った方もいるかもしれません。1つのブランチ/タグで複数環境にデプロイさせてしまうと、例えば本番環境をロールバックしたいだけなのにステージングもロールバックしなくてはいけないように見えます。
確かにシステムの構成によってはその問題が発生するかもしれません。ただ、AWS SAMの場合ロールバックは簡単です。 aws cloudformation package
コマンドで生成されたAWS SAMテンプレートを再度適用すればいいからです。そして、CircleCIが生成したテンプレートはstore_artifactsステップで保存しておけば簡単に後から参照できます。
- store_artifacts: path: packaged.yml
ロールバックが必要な場合、このファイルをローカルPCにダウンロードし aws cloudformation deploy
コマンドを実行することで簡単に以前の状態に戻すことが可能です。
まとめ
いかがだったでしょうか。
CircleCIのManual Approvalを利用したシンプルなブランチ/タグ運用についてご紹介しました。CI/CDは日々の開発効率に関わってくるので今後も改善していきたいなと思っています。またネタが貯まったらご紹介できれば。
本エントリがみなさんの参考になれば幸いに思います。